home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Qu.......ke Neue Level
/
KroGer Software GmbH - Qu_ke.iso
/
UTILITY
/
PRG8.ZIP
/
F_SPRITE.C
< prev
next >
Wrap
C/C++ Source or Header
|
1996-03-03
|
14KB
|
473 lines
/*
* Copyright (C) 1996 by Raphael Quinet. All rights reserved.
*
* Permission to use, copy, modify, and distribute this software and
* its documentation for any purpose and without fee is hereby
* granted, provided that the above copyright notice appear in all
* copies and that both that copyright notice and this permission
* notice appear in supporting documentation. If more than a few
* lines of this code are used in a program which displays a copyright
* notice or credit notice, the following acknowledgment must also be
* displayed on the same screen: "This product includes software
* developed by Raphael Quinet for use in the Quake Editing Utilities
* project." THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT EXPRESS OR
* IMPLIED WARRANTY.
*
* More information about the QEU project can be found on the WWW:
* "http://www.montefiore.ulg.ac.be/~quinet/games/editing.html" or by
* mail: Raphael Quinet, 9 rue des Martyrs, B-4550 Nandrin, Belgium.
*/
/*
* F_SPRITE.C - Read and write Quake sprite files.
*/
/*
* NOTE: There are still some parts of the sprite format which are a
* bit strange for me. I could be wrong for the multi-image
* stuff, even if it works rather well. The test version of
* Quake doesn't contain enough "special" sprites like the
* torches (s_torch*.spr) and the shots (shots.spr), so I'm
* not sure if my guesses are correct.
* This piece of code is probably more complex than it should
* be, but at least it works. More or less.
*/
#include "qeu.h"
#include "q_misc.h"
#include "q_files.h"
#include "f_sprite.h"
/*! #include <math.h> */
/*
* Create a new, empty sprite.
*/
SpritePtr NewSprite()
{
SpritePtr sprite;
sprite = (SpritePtr)QMalloc((UInt32)sizeof(struct SpriteInfo));
sprite->unknown1 = 0L;
sprite->unknown2 = 0L;
sprite->radius = 0.0;
sprite->maxwidth = 0;
sprite->maxheight = 0;
sprite->numframes = 0;
sprite->frames = NULL;
sprite->unknown4 = 0L;
sprite->unknown5 = 0L;
return sprite;
}
/*
* Discard a sprite and free memory.
*/
void FreeSprite(SpritePtr sprite)
{
UInt16 i, j;
if (sprite->numframes > 0)
for (i = 0; i < sprite->numframes; i++)
if (sprite->frames[i].images != NULL)
{
if (sprite->frames[i].numimages == 0)
{
if (sprite->frames[i].images[0].bitmap.data != NULL)
QFree(sprite->frames[i].images[0].bitmap.data);
}
else
{
for (j = 0; j < sprite->frames[i].numimages; j++)
if (sprite->frames[i].images[j].bitmap.data != NULL)
QFree(sprite->frames[i].images[j].bitmap.data);
}
}
QFree(sprite);
}
/*
* Add an image to a sprite. The bitmap data is copied and can be
* freed after having called this function. If "framenum" is negative
* and "multi" is FALSE, a new frame is created, containing a single
* image. If "framenum" is negative and "multi" is TRUE, a new
* multi-image frame is created, using the value of "unknown" for the
* first image. If "framenum" is greater or equal to zero and "multi"
* is TRUE, the image is added to an existing multi-image frame.
* Returns the number of the frame that was added or modified.
*/
UInt16 AddSpriteImage(SpritePtr sprite, Int16 framenum, Bool multi,
Float32 unknown, Int16 xoffset, Int16 yoffset,
BitMap *bmptr)
{
UInt16 n, i;
n = sprite->numframes;
if (framenum < 0)
{
if (n == 0)
sprite->frames = (SpriteFrame *)QMalloc((UInt32)sizeof(SpriteFrame));
else
sprite->frames = (SpriteFrame *)QRealloc(sprite->frames,
(UInt32)(n + 1) * (UInt32)sizeof(SpriteFrame));
if (multi == TRUE)
{
sprite->frames[n].numimages = 1;
sprite->frames[n].unknown = (Float32 *)QMalloc(
(UInt32)sizeof(Float32));
}
else
sprite->frames[n].numimages = 0;
sprite->frames[n].images = (SpriteImage *)QMalloc(
(UInt32)sizeof(SpriteImage));
sprite->numframes = n + 1;
i = 0;
}
else
{
if (n == 0 || framenum >= n)
ProgError("BUG: cannot add an image to a non-existing frame (%d, %d)",
n, framenum);
n = framenum;
i = sprite->frames[n].numimages;
if (i == 0)
{
sprite->frames[n].unknown = (Float32 *)QMalloc(
(UInt32)sizeof(Float32));
sprite->frames[n].images = (SpriteImage *)QMalloc(
(UInt32)sizeof(SpriteImage));
}
else
{
sprite->frames[n].unknown = (Float32 *)QRealloc(
sprite->frames[n].unknown, (UInt32)(i + 1)
* (UInt32)sizeof(Float32));
sprite->frames[n].images = (SpriteImage *)QRealloc(
sprite->frames[n].images, (UInt32)(i + 1)
* (UInt32)sizeof(SpriteImage));
}
sprite->frames[n].unknown[i] = unknown;
sprite->frames[n].numimages = i + 1;
}
sprite->frames[n].images[i].xoffset = xoffset;
sprite->frames[n].images[i].yoffset = yoffset;
sprite->frames[n].images[i].bitmap.width = bmptr->width;
sprite->frames[n].images[i].bitmap.height = bmptr->height;
sprite->frames[n].images[i].bitmap.data = QMemDup(bmptr->data,
(UInt32)(bmptr->width) * (UInt32)(bmptr->height));
return n;
}
/*
* Read a sprite into memory. The optional offset to the start of the
* sprite data is given in "offset" (so that one can read the sprite
* data from an individual file as well as from within a WAD2 or PACK
* file).
*/
SpritePtr ReadSprite(FILE *file, UInt32 offset)
{
SpritePtr sprite;
UInt32 numframes;
UInt16 n, i, f = 0;
UInt32 u, w, h;
Int32 x, y;
BitMap *bmptr;
Float32 *unknown;
if (file == NULL)
return NULL;
if ((fseek(file, offset, SEEK_SET) < 0)
|| (ReadMagic(file) != FTYPE_SPRITE))
return NULL;
sprite = NewSprite();
if ((ReadInt32(file, &(sprite->unknown1)) == FALSE)
|| (ReadInt32(file, &(sprite->unknown2)) == FALSE)
|| (ReadFloat32(file, &(sprite->radius)) == FALSE)
|| (ReadInt32(file, &w) == FALSE)
|| (w > 65535L)
|| (ReadInt32(file, &h) == FALSE)
|| (h > 65535L)
|| (ReadInt32(file, &numframes) == FALSE)
|| (numframes > 65535L)
|| (ReadInt32(file, &(sprite->unknown4)) == FALSE)
|| (ReadInt32(file, &(sprite->unknown5)) == FALSE))
{
FreeSprite(sprite);
return NULL;
}
sprite->maxwidth = (UInt16)w;
sprite->maxheight = (UInt16)h;
if (numframes == 0L)
return sprite;
bmptr = NewBitMap();
bmptr->data = (UInt8 huge *)QMalloc(w * h);
for (n = 0; n < (UInt16)numframes; n++)
{
if (ReadInt32(file, &u) == FALSE)
{
FreeBitMap(bmptr);
FreeSprite(sprite);
return NULL;
}
if (u != 0)
{
printf("(Frame %d) u = 0x%lx\n", n, u);
if (ReadInt32(file, &u) == FALSE)
{
FreeBitMap(bmptr);
FreeSprite(sprite);
return NULL;
}
unknown = (Float32 *)QMalloc(u * (UInt32)sizeof(Float32));
for (i = 0; i < (UInt16)u; i++)
if (ReadFloat32(file, &(unknown[i])) == FALSE)
{
QFree(unknown);
FreeBitMap(bmptr);
FreeSprite(sprite);
return NULL;
}
for (i = 0; i < (UInt16)u; i++)
{
if ((ReadInt32(file, &x) == FALSE)
|| (x > 32767L)
|| (x < -32768L)
|| (ReadInt32(file, &y) == FALSE)
|| (y > 32767L)
|| (y < -32768L)
|| (ReadInt32(file, &w) == FALSE)
|| (w == 0)
|| (w > (UInt32)(sprite->maxwidth))
|| (ReadInt32(file, &h) == FALSE)
|| (h == 0)
|| (h > (UInt32)(sprite->maxheight))
|| (ReadBytes(file, bmptr->data, w * h) == FALSE))
{
QFree(unknown);
FreeBitMap(bmptr);
FreeSprite(sprite);
return NULL;
}
bmptr->width = (UInt16)w;
bmptr->height = (UInt16)h;
if (i == 0)
f = AddSpriteImage(sprite, -1, TRUE, unknown[i],
(Int16)x, (Int16)y, bmptr);
else
f = AddSpriteImage(sprite, f, TRUE, unknown[i],
(Int16)x, (Int16)y, bmptr);
}
QFree(unknown);
}
else
{
if ((ReadInt32(file, &x) == FALSE)
|| (x > 32767L)
|| (x < -32768L)
|| (ReadInt32(file, &y) == FALSE)
|| (y > 32767L)
|| (y < -32768L)
|| (ReadInt32(file, &w) == FALSE)
|| (w == 0)
|| (w > (UInt32)(sprite->maxwidth))
|| (ReadInt32(file, &h) == FALSE)
|| (h == 0)
|| (h > (UInt32)(sprite->maxheight))
|| (ReadBytes(file, bmptr->data, w * h) == FALSE))
{
FreeBitMap(bmptr);
FreeSprite(sprite);
return NULL;
}
bmptr->width = (UInt16)w;
bmptr->height = (UInt16)h;
AddSpriteImage(sprite, -1, FALSE, 0.0, (Int16)x, (Int16)y, bmptr);
}
}
FreeBitMap(bmptr);
return sprite;
}
/*
* Print the structure of a sprite in "outf".
*/
void DumpSprite(FILE *outf, SpritePtr sprite)
{
UInt16 n, i;
if (outf == NULL || sprite == NULL)
return;
fprintf(outf, "Unknown1 = 0x%lx\n", sprite->unknown1);
fprintf(outf, "Unknown2 = 0x%lx\n", sprite->unknown2);
fprintf(outf, "Radius = %f\n", sprite->radius);
fprintf(outf, "MaxWidth = %u\n", sprite->maxwidth);
fprintf(outf, "MaxHeight = %u\n", sprite->maxheight);
fprintf(outf, "NumFrames = %u\n", sprite->numframes);
fprintf(outf, "Unknown4 = 0x%lx\n", sprite->unknown4);
fprintf(outf, "Unknown5 = 0x%lx\n", sprite->unknown5);
for (n = 0; n < sprite->numframes; n++)
{
printf("Frame %d:\n", n);
if (sprite->frames[n].numimages == 0)
{
fprintf(outf, " x offset = %d\n",
sprite->frames[n].images[0].xoffset);
fprintf(outf, " y offset = %d\n",
sprite->frames[n].images[0].yoffset);
fprintf(outf, " width = %u\n",
sprite->frames[n].images[0].bitmap.width);
fprintf(outf, " height = %u\n",
sprite->frames[n].images[0].bitmap.height);
}
else
for (i = 0; i < sprite->frames[n].numimages; i++)
{
printf(" Image %d:\n", i);
fprintf(outf, " unknown = %f\n",
sprite->frames[n].unknown[i]);
fprintf(outf, " x offset = %d\n",
sprite->frames[n].images[i].xoffset);
fprintf(outf, " y offset = %d\n",
sprite->frames[n].images[i].yoffset);
fprintf(outf, " width = %u\n",
sprite->frames[n].images[i].bitmap.width);
fprintf(outf, " height = %u\n",
sprite->frames[n].images[i].bitmap.height);
}
}
fprintf(outf, "End.\n");
}
/*
* Adjust the sprite information according to the width and height
* of the frames. This should be called before saving a sprite.
*/
void AdjustSpriteInfo(SpritePtr sprite)
{
UInt16 n, i;
Float32 w, h;
Bool modified = FALSE;
for (n = 0; n < sprite->numframes; n++)
if (sprite->frames[n].numimages == 0)
{
if (sprite->frames[n].images[0].bitmap.width > sprite->maxwidth)
{
sprite->maxwidth = sprite->frames[n].images[0].bitmap.width;
modified = TRUE;
}
if (sprite->frames[n].images[0].bitmap.height > sprite->maxheight)
{
sprite->maxheight = sprite->frames[n].images[0].bitmap.height;
modified = TRUE;
}
}
else
for (i = 0; i < sprite->frames[n].numimages; i++)
{
if (sprite->frames[n].images[i].bitmap.width > sprite->maxwidth)
{
sprite->maxwidth = sprite->frames[n].images[i].bitmap.width;
modified = TRUE;
}
if (sprite->frames[n].images[i].bitmap.height > sprite->maxheight)
{
sprite->maxheight = sprite->frames[n].images[i].bitmap.height;
modified = TRUE;
}
}
if (modified == TRUE)
{
w = (Float32)(sprite->maxwidth / 2);
h = (Float32)(sprite->maxheight / 2);
/*!
sprite->radius = sqrt(w * w + h * h);
*/
}
/*! I don't know how to adjust the other fields (unknown{1,2,4,5}) */
}
/*
* Save sprite to a file (all frames).
* The number of bytes written is returned (0 if an error occured).
*/
UInt32 SaveSprite(FILE *file, SpritePtr sprite)
{
UInt16 n, i;
Int32 x, y;
UInt32 u, w, h;
UInt32 size;
if (sprite == NULL)
return 0L;
w = (UInt32)(sprite->maxwidth);
h = (UInt32)(sprite->maxheight);
u = (UInt32)(sprite->numframes);
if ((WriteBytes(file, "IDSP", 4) == FALSE)
|| (WriteInt32(file, &(sprite->unknown1)) == FALSE)
|| (WriteInt32(file, &(sprite->unknown2)) == FALSE)
|| (WriteFloat32(file, &(sprite->radius)) == FALSE)
|| (WriteInt32(file, &w) == FALSE)
|| (WriteInt32(file, &h) == FALSE)
|| (WriteInt32(file, &u) == FALSE)
|| (WriteInt32(file, &(sprite->unknown4)) == FALSE)
|| (WriteInt32(file, &(sprite->unknown5)) == FALSE))
return 0L;
size = 36L;
for (n = 0; n < sprite->numframes; n++)
{
if (sprite->frames[n].numimages == 0)
{
u = 0;
x = (Int32)(sprite->frames[n].images[0].xoffset);
y = (Int32)(sprite->frames[n].images[0].yoffset);
if ((WriteInt32(file, &u) == FALSE)
|| (WriteInt32(file, &x) == FALSE)
|| (WriteInt32(file, &y) == FALSE))
return 0L;
u = SaveBitMap(file, &(sprite->frames[n].images[0].bitmap));
if (u == 0L)
return 0L;
size += 12L + u;
}
else
{
/* hack... */
if ((sprite->frames[n].numimages >= 2)
&& (sprite->frames[n].unknown[1] > 0.1))
u = 0x1000000;
else
u = 0x0000001;
if (WriteInt32(file, &u) == FALSE)
return 0L;
u = (UInt32)(sprite->frames[n].numimages);
if (WriteInt32(file, &u) == FALSE)
return 0L;
size += 8L;
for (i = 0; i < sprite->frames[n].numimages; i++)
if (WriteFloat32(file, &(sprite->frames[n].unknown[i])) == FALSE)
return 0L;
for (i = 0; i < sprite->frames[n].numimages; i++)
{
x = (Int32)(sprite->frames[n].images[i].xoffset);
y = (Int32)(sprite->frames[n].images[i].yoffset);
if ((WriteInt32(file, &x) == FALSE)
|| (WriteInt32(file, &y) == FALSE))
return 0L;
u = SaveBitMap(file, &(sprite->frames[n].images[i].bitmap));
if (u == 0L)
return 0L;
size += 12 + u;
}
}
}
return size;
}
/* end of file */